home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue59 / System / TarUnit.pas < prev   
Encoding:
Pascal/Delphi Source File  |  2000-06-08  |  7.3 KB  |  239 lines

  1. unit TarUnit;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  7.   StdCtrls, ComCtrls;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     Files: TListView;
  12.     Button1: TButton;
  13.     OpenDialog1: TOpenDialog;
  14.     Label1: TLabel;
  15.     SaveDialog1: TSaveDialog;
  16.     procedure FilesDblClick(Sender: TObject);
  17.     procedure Button1Click(Sender: TObject);
  18.   private
  19.     { Private declarations }
  20.   public
  21.     { Public declarations }
  22.   end;
  23.  
  24. var
  25.   Form1: TForm1;
  26.  
  27. implementation
  28.  
  29. {$R *.DFM}
  30.  
  31. type
  32.     TTarFileEntry = class (TObject)
  33.     private
  34.         name, uid, gid: String;
  35.         mode, size: Integer;
  36.         mtime: TDateTime;
  37.         FileOffset: Integer;
  38.     end;
  39.  
  40.     TTarFile = class (TObject)
  41.     private
  42.         FileList: TStringList;
  43.     public
  44.         constructor Create (const FileName: String);
  45.         destructor Destroy; override;
  46.     end;
  47.  
  48. // TTarFile
  49.  
  50. function OctalToInt (Str: String): Integer;
  51. var
  52.     Idx: Integer;
  53. begin
  54.     Result := 0;  Str := Trim (Str);
  55.     for Idx := 1 to Length (Str) do begin
  56.         if not (Str [Idx] in ['0'..'7']) then Exit;
  57.         Result := (Result shl 3) + Ord (Str [Idx]) - Ord ('0');
  58.     end;
  59. end;
  60.  
  61. function UnixTimeToFileTime (UnixDateTime: TLargeInteger): TDateTime;
  62. var
  63.     Time: Integer;
  64.     LocalTime: TFileTime;
  65.     FileTime: TFileTime absolute UnixDateTime;
  66. begin
  67.     UnixDateTime := (UnixDateTime + 11644473600) * 10000000;
  68.     FileTimeToLocalFileTime (FileTime, LocalTime);                           // WIN32!!
  69.     FileTimeToDosDateTime (LocalTime, LongRec (Time).Hi, LongRec (Time).Lo); // WIN32!!
  70.     Result := FileDateToDateTime (Time);
  71. end;
  72.  
  73. function PermissionsToStr (Perm: Integer): String;
  74.  
  75.     function PermFlags (bits: Integer): String;
  76.     begin
  77.         Result := '---';
  78.         if (bits and 4) <> 0 then Result [1] := 'r';
  79.         if (bits and 2) <> 0 then Result [2] := 'w';
  80.         if (bits and 1) <> 0 then Result [3] := 'x';
  81.     end;
  82.  
  83. begin
  84.     // Display order is owner-group-other
  85.     Result := PermFlags (Perm shr 6) + PermFlags (Perm shr 3) + PermFlags (Perm);
  86. end;
  87.  
  88. constructor TTarFile.Create (const FileName: String);
  89. type
  90.     TarHeader = record
  91.         name: array [0..99] of Char;            // name of the file
  92.         mode: array [0..7] of Char;             // permission bits
  93.         uid: array [0..7] of Char;              // owner - user ID
  94.         gid: array [0..7] of Char;              // owner - group ID
  95.         size: array [0..11] of Char;            // size of this file
  96.         mtime: array [0..11] of Char;           // file modification time
  97.         chksum: array [0..7] of Char;           // checksum for file header
  98.         linkflag: Char;
  99.         linkname: array [0..99] of Char;
  100.         magic: array [0..7] of Char;
  101.         uname: array [0..31] of Char;
  102.         gname: array [0..31] of Char;
  103.         devmajor: array [0..7] of Char;
  104.         devminor: array [0..7] of Char;
  105.     end;
  106.  
  107. var
  108.     fs: TFileStream;
  109.     Header: TarHeader;
  110.     NextBlock: Integer;
  111.     entry: TTarFileEntry;
  112. begin
  113.     Inherited Create;
  114.     FileList := TStringList.Create;
  115.     if FileExists (FileName) then begin
  116.         fs := TFileStream.Create (FileName, fmOpenRead);
  117.         try
  118.             while fs.Position < fs.Size do begin
  119.                 NextBlock := fs.Position + 512;
  120.                 fs.Read (Header, sizeof (Header));
  121.                 if Header.name = '' then break;
  122.  
  123.                 entry := TTarFileEntry.Create;
  124.                 entry.name  := Header.name;
  125.                 entry.mode  := OctalToInt (Header.mode);
  126.                 entry.size  := OctalToInt (Header.size);
  127.                 entry.mtime := UnixTimeToFileTime (OctalToInt (Header.mtime));
  128.                 entry.FileOffset := NextBlock;
  129.  
  130.                 if Trim (Header.magic) = 'ustar' then begin
  131.                     entry.uid   := Trim (Header.uname);
  132.                     entry.gid   := Trim (Header.gname);
  133.                 end else begin
  134.                     entry.uid   := Trim (Header.uid);
  135.                     entry.gid   := Trim (Header.gid);
  136.                 end;
  137.  
  138.                 FileList.AddObject (entry.name, entry);
  139.  
  140.                 fs.Position := NextBlock + ((entry.size + 511) div 512) * 512;
  141.             end;
  142.         finally
  143.             fs.Free;
  144.         end;
  145.     end;
  146. end;
  147.  
  148. destructor TTarFile.Destroy;
  149. var
  150.     Idx: Integer;
  151. begin
  152.     for Idx := FileList.Count - 1 downto 0 do
  153.         FileList.Objects [Idx].Free;
  154.     FileList.Free;
  155.     Inherited Destroy;
  156. end;
  157.  
  158. procedure TForm1.FilesDblClick(Sender: TObject);
  159. var
  160.     Item: TListItem;
  161.     FileName: String;
  162.     Size, Offset: Integer;
  163.  
  164.     function DeUnix (const Path: String): String;
  165.     var
  166.         Idx: Integer;
  167.     begin
  168.         Result := Path;
  169.         for Idx := 1 to Length (Result) do
  170.             if Result [Idx] = '/' then Result [Idx] := '\';
  171.     end;
  172.  
  173.     procedure ExtractFile (const Archive, Dest: String; Offset, Size: Integer);
  174.     var
  175.         sArchive, sDest: TFileStream;
  176.     begin
  177.         sArchive := TFileStream.Create (Archive, fmOpenRead);
  178.         try
  179.             sDest := TFileStream.Create (Dest, fmCreate);
  180.             try
  181.                 sArchive.Position := Offset;
  182.                 sDest.CopyFrom (sArchive, Size);
  183.             finally
  184.                 sDest.Free;
  185.             end;
  186.         finally
  187.             sArchive.Free;
  188.         end;
  189.     end;
  190.  
  191. begin
  192.     if Files.Items.Count = 0 then ShowMessage ('Please open a tar file first') else begin
  193.         Item := Files.Selected;
  194.         if Item <> Nil then begin
  195.             Size := StrToInt (Item.SubItems [2]);
  196.             if Size = 0 then ShowMessage ('Can only extract physical files') else begin
  197.                 Offset := StrToInt (Item.SubItems [6]);
  198.                 FileName := ExtractFileName (DeUnix (Item.Caption));
  199.                 if MessageDlg ('Extract ' + FileName + '?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin
  200.                     SaveDialog1.FileName := FileName;
  201.                     if SaveDialog1.Execute then ExtractFile (OpenDialog1.FileName, SaveDialog1.FileName, Offset, Size);
  202.                 end;
  203.             end;
  204.         end;
  205.     end;
  206. end;
  207.  
  208. procedure TForm1.Button1Click(Sender: TObject);
  209. var
  210.     Idx: Integer;
  211.     tar: TTarFile;
  212.     Item: TListItem;
  213.     Entry: TTarFileEntry;
  214. begin
  215.     if OpenDialog1.Execute then begin
  216.         tar := TTarFile.Create (OpenDialog1.FileName);
  217.         try
  218.             Files.Items.Clear;
  219.             for Idx := 0 to tar.FileList.Count - 1 do begin
  220.                 Entry := TTarFileEntry (tar.FileList.Objects [Idx]);
  221.                 Item := Files.Items.Add;
  222.                 Item.Caption := Entry.name;
  223.                 Item.SubItems.Add (FormatDateTime ('dd/mm/yyyy', Entry.mtime));
  224.                 Item.SubItems.Add (FormatDateTime ('hh:mm:ss', Entry.mtime));
  225.                 Item.SubItems.Add (IntToStr (Entry.size));
  226.                 Item.SubItems.Add (PermissionsToStr (Entry.mode));
  227.                 Item.SubItems.Add (Entry.uid);
  228.                 Item.SubItems.Add (Entry.gid);
  229.                 if Entry.size <> 0 then Item.SubItems.Add ('$' + IntToHex (Entry.FileOffset, 8));
  230.             end;
  231.         finally
  232.             tar.Free;
  233.             Label1.Visible := Files.Items.Count > 0;
  234.         end;
  235.     end;
  236. end;
  237.  
  238. end.
  239.